//
//  GHWeiboEngine.m
//  notebook
//
//  Created by 诗彬 刘 on 12-5-9.
//  Copyright (c) 2012年 ifuninfo. All rights reserved.
//

#import <QuartzCore/QuartzCore.h>
#import "JSONKit.h"
#import "GHWeiboEngine.h"
#import "SFHFKeychainUtils.h"
#import "SynthesizeSingleton.h"
#import "EasyBuy.h"


NSString *const kGHWeiboEngineLoginedNotification = @"kGHWeiboEngineLoginedNotification";

@implementation NSString(WeiboUlti)
+ (NSString *)WBParamstringWithDictionary:(NSDictionary *)dict{
    NSMutableArray *pairs = [NSMutableArray array];
    for (NSString *key in [dict keyEnumerator])
    {
        if (!([[dict valueForKey:key] isKindOfClass:[NSString class]])){
            continue;
        }
        [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, [[dict objectForKey:key] WBUrlEncodeString]]];
    }
    return [pairs componentsJoinedByString:@"&"];
}

- (NSString *)WBUrlEncodeString{
    NSString *newString = [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) autorelease];
    if (newString) {
        return newString;
    }
    return @"";
}

+ (NSString *)WBRequestURLWithBaseURL:(NSString *)baseURL params:(NSDictionary *)params httpMethod:(NSString *)httpMethod{
    if (![httpMethod isEqualToString:@"GET"]){
        return [[baseURL copy] autorelease];
    }
    
    NSURL *parsedURL = [NSURL URLWithString:[[baseURL copy] autorelease]];
	NSString *queryPrefix = parsedURL.query ? @"&" : @"?";
    NSString *paramString = [self WBParamstringWithDictionary:params];
	
	return [NSString stringWithFormat:@"%@%@%@", baseURL, queryPrefix, paramString];
}
@end

@class GHWeiboAuthorizeWebView;
@protocol AuthorizeWebViewDelegate <NSObject>
- (void)authorizeWebView:(GHWeiboAuthorizeWebView *)webView didReceiveAuthorizeCode:(NSString *)code;
- (void)authorizeWebViewCanceled:(GHWeiboAuthorizeWebView *)webView;
@end

@interface GHWeiboAuthorizeWebView : UIView <UIWebViewDelegate>{
    UIView *panelView;
    UIView *containerView;
    UIActivityIndicatorView *indicatorView;
	UIWebView *webView;
    UIInterfaceOrientation previousOrientation;
    id<AuthorizeWebViewDelegate> delegate;
}
@property (nonatomic, assign) id<AuthorizeWebViewDelegate> delegate;
- (void)loadRequestWithURL:(NSURL *)url;
- (void)show:(BOOL)animated;
- (void)hide:(BOOL)animated;
@end

@implementation GHWeiboAuthorizeWebView

@synthesize delegate;

#pragma mark - WBAuthorizeWebView Life Circle

- (id)initWithFrame:(CGRect)frame{
    UIView *rootView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
    if (self = [super initWithFrame:rootView.bounds]){
        // background settings
        [self setBackgroundColor:[UIColor clearColor]];
        [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
        
        // add the panel view
        panelView = [[UIView alloc] initWithFrame:CGRectMake(10,10,self.frame.size.width-20, self.frame.size.height-20)];
        [panelView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
        [panelView setBackgroundColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.55]];
        [[panelView layer] setMasksToBounds:NO];
        [[panelView layer] setCornerRadius:10.0];
        [self addSubview:panelView];
        
        // add the conainer view
        containerView=[[UIView alloc]initWithFrame:CGRectMake(10,10,panelView.frame.size.width-20,panelView.frame.size.height-20)];
        [containerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
        [[containerView layer] setBorderColor:[UIColor colorWithRed:0. green:0. blue:0. alpha:0.7].CGColor];
        [[containerView layer] setBorderWidth:1.0];
        
        
        // add the web view
        webView = [[UIWebView alloc] initWithFrame:containerView.bounds];
        [webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
		[webView setDelegate:self];
		[containerView addSubview:webView];
        
        [panelView addSubview:containerView];
        
        indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        indicatorView.center = CGPointMake(panelView.frame.size.width/2, panelView.frame.size.height/2);
        [indicatorView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin];
        [panelView addSubview:indicatorView];
        
        UIImage *image = [UIImage imageNamed:@"sinaweibo_close_btn"];
        
        UIButton *close = [UIButton buttonWithType:UIButtonTypeCustom];
        [close setBackgroundImage:image forState:UIControlStateNormal];
        [close sizeToFit];
        [close addTarget:self action:@selector(onCloseButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
        close.center = CGPointMake(containerView.frame.size.width - close.frame.size.width/2,close.frame.size.height/2);
        [containerView addSubview:close];
    }
    return self;
}

- (void)dealloc{
    [panelView release], panelView = nil;
    [containerView release], containerView = nil;
    [webView release], webView = nil;
    [indicatorView release], indicatorView = nil;
    
    [super dealloc];
}

#pragma mark Actions

- (void)onCloseButtonTouched:(id)sender{
    [self hide:YES];
    if ([delegate respondsToSelector:@selector(authorizeWebViewCanceled:)]){
        [delegate authorizeWebViewCanceled:self];
    }
}

#pragma mark Dismiss

- (void)hideAndCleanUp{
	[self removeFromSuperview];
}

#pragma mark - WBAuthorizeWebView Public Methods

- (void)loadRequestWithURL:(NSURL *)url{
    NSURLRequest *request =[NSURLRequest requestWithURL:url
                                            cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                        timeoutInterval:60.0];
    [webView loadRequest:request];
}

- (void)show:(BOOL)animated{
    UIView  *window = [UIApplication sharedApplication].keyWindow.rootViewController.view;
  	[window addSubview:self];
    if (animated){
        [panelView setAlpha:0];
        [panelView setTransform:CGAffineTransformMakeScale(0.3, 0.3)];
        [UIView animateWithDuration:0.2
                         animations:^{
                             [panelView setAlpha:0.5];
                             [panelView setTransform:CGAffineTransformMakeScale(1.1, 1.1)];
                         } 
                         completion:^(BOOL finished) {
                             [UIView animateWithDuration:0.13
                                              animations:^{
                                                  [panelView setAlpha:0.8];
                                                  [panelView setTransform:CGAffineTransformMakeScale(0.9, 0.9)];
                                              } 
                                              completion:^(BOOL finished) {
                                                  [UIView animateWithDuration:0.13
                                                                   animations:^{
                                                                       [panelView setAlpha:1];
                                                                       [panelView setTransform:CGAffineTransformIdentity]; 
                                                                   }];
                                              }];
                         }];
        
    }
}

- (void)hide:(BOOL)animated{
	if (animated){
        [UIView animateWithDuration:0.3
                         animations:^{
                             [self setAlpha:0];
                         } completion:^(BOOL finished) {
                             [self hideAndCleanUp];
                         }];
	}else {
        [self hideAndCleanUp];  
    } 
}

#pragma mark - UIWebViewDelegate Methods

- (void)webViewDidStartLoad:(UIWebView *)aWebView{
	[indicatorView startAnimating];
}

- (void)webViewDidFinishLoad:(UIWebView *)aWebView{
	[indicatorView stopAnimating];
}

- (void)webView:(UIWebView *)aWebView didFailLoadWithError:(NSError *)error{
    [indicatorView stopAnimating];
}

- (BOOL)webView:(UIWebView *)aWebView 
shouldStartLoadWithRequest:(NSURLRequest *)request
 navigationType:(UIWebViewNavigationType)navigationType{
    NSRange range = [request.URL.absoluteString rangeOfString:@"code="];
    if (range.location != NSNotFound){
        NSString *code = [request.URL.absoluteString substringFromIndex:range.location + range.length];
        if ([code isEqualToString:@"21330"]) {
            if ([delegate respondsToSelector:@selector(authorizeWebViewCanceled:)]){
                [delegate authorizeWebViewCanceled:self];
            }
        }else if ([delegate respondsToSelector:@selector(authorizeWebView:didReceiveAuthorizeCode:)]){
                [delegate authorizeWebView:self didReceiveAuthorizeCode:code];
        }
    }
    return YES;
}

@end

@interface GHWeiboRequest(){
    NSURLConnection *connection;
    NSMutableData   *responseData;
    BOOL            connectionDone;
}
- (NSData *)postData;
- (void)handleResponseData:(NSData *)data;
- (id)getObjectFromJsonData:(NSData *)data error:(NSError **)error;
- (id)errorWithCode:(NSInteger)code userInfo:(NSDictionary *)userInfo;
- (void)failedWithError:(NSError *)error;
- (NSURLConnection *)beginConnection;
@end

NSString *const kWBRequestResultData = @"kWBRequestResultData";
NSString *const kWBRequestResultJsonData = @"kWBRequestResultJsonData";
NSString *const kWBRequestResultError =  @"kWBRequestResultError";
NSString *const kWBRequestResultStatus = @"kWBRequestResultStatus";

@implementation GHWeiboRequest
@synthesize url;
@synthesize identifier;
@synthesize params;
@synthesize delegate = _delegate;
@synthesize weiboEngine = _weiboEngine;
@synthesize requestResult;
+ (GHWeiboRequest *)requestWithURL:(NSString *)url 
                        httpMethod:(NSString *)httpMethod 
                            params:(NSDictionary *)params
                      postDataType:(WBRequestPostDataType)postDataType
                  httpHeaderFields:(NSDictionary *)httpHeaderFields
                        identifier:(NSString *)identifier
                          delegate:(id<GHWeiboRequestDelegate>)delegate{
    
    return [[[GHWeiboRequest alloc] initWithURL:url
                                     httpMethod:httpMethod
                                         params:params
                                   postDataType:postDataType
                               httpHeaderFields:httpHeaderFields
                                     identifier:identifier
                                       delegate:delegate 
                                  needAuthorize:NO] autorelease];
}

+ (GHWeiboRequest *)authorizedRequestWithURL:(NSString *)url
                                  httpMethod:(NSString *)httpMethod 
                                      params:(NSDictionary *)params
                                postDataType:(WBRequestPostDataType)postDataType
                            httpHeaderFields:(NSDictionary *)httpHeaderFields
                                  identifier:(NSString *)identifier
                                    delegate:(id<GHWeiboRequestDelegate>)delegate{
    return [[[GHWeiboRequest alloc] initWithURL:url
                                     httpMethod:httpMethod
                                         params:params
                                   postDataType:postDataType
                               httpHeaderFields:httpHeaderFields
                                     identifier:identifier
                                       delegate:delegate 
                                  needAuthorize:YES] autorelease];
}

+ (GHWeiboRequest *)apiRequestWithMethod:(NSString *)method
                              httpMethod:(NSString *)httpMethod 
                                  params:(NSDictionary *)params
                            postDataType:(WBRequestPostDataType)postDataType
                        httpHeaderFields:(NSDictionary *)httpHeaderFields
                              identifier:(NSString *)identifier
                                delegate:(id<GHWeiboRequestDelegate>)delegate
                           needAuthorize:(BOOL)need{
    NSString *url = [NSString stringWithFormat:@"%@%@",kWBSDKAPIDomain,method];
    return [[[GHWeiboRequest alloc] initWithURL:url
                                     httpMethod:httpMethod
                                         params:params
                                   postDataType:postDataType
                               httpHeaderFields:httpHeaderFields
                                     identifier:identifier
                                       delegate:delegate 
                                  needAuthorize:need] autorelease];
}

+ (GHWeiboRequest *)uploadApiRequestWithMethod:(NSString *)method
                              httpMethod:(NSString *)httpMethod
                                  params:(NSDictionary *)params
                            postDataType:(WBRequestPostDataType)postDataType
                        httpHeaderFields:(NSDictionary *)httpHeaderFields
                              identifier:(NSString *)identifier
                                delegate:(id<GHWeiboRequestDelegate>)delegate
                           needAuthorize:(BOOL)need{
    
    NSString *url = [NSString stringWithFormat:@"%@%@",kWBSDKUploadAPIDomain,method];
    return [[[GHWeiboRequest alloc] initWithURL:url
                                     httpMethod:httpMethod
                                         params:params
                                   postDataType:postDataType
                               httpHeaderFields:httpHeaderFields
                                     identifier:identifier
                                       delegate:delegate
                                  needAuthorize:need] autorelease];   
}

- (id)initWithURL:(NSString *)url_
       httpMethod:(NSString *)httpMethod_
           params:(NSDictionary *)params_
     postDataType:(WBRequestPostDataType)postDataType_
 httpHeaderFields:(NSDictionary *)httpHeaderFields_
       identifier:(NSString *)identifier_
         delegate:(id<GHWeiboRequestDelegate>)delegate 
    needAuthorize:(BOOL)need{
    self = [self init];
    if (self) {
        url = [url_ copy];
        httpHeaderFields = [httpHeaderFields_ copy];
        httpMethod = [httpMethod_ copy];
        params = [params_ copy];
        postDataType = postDataType_;
        identifier = [identifier_ copy];
        needAuthorize = need;
        self.delegate = delegate;
    }
    return self;
}

- (void)dealloc{
    self.delegate = nil;
    [requestResult release],requestResult = nil;
    [identifier release],identifier = nil;
    [url release],url = nil;
    [params release],params = nil;
    [httpMethod release],httpMethod = nil;
    [httpHeaderFields release],httpHeaderFields = nil;
    [connection cancel],[connection release],connection = nil;
    [responseData release],responseData = nil;
    [super dealloc];
}

- (void)main{
    @autoreleasepool {
        if (needAuthorize&&!self.weiboEngine.accessToken) {
            [self failedWithError:[self errorWithCode:kWBSDKErrorCodeAuthorizeError userInfo:nil]];
            return;
        }
        connection = [[self beginConnection] retain];
        if (connection) {
            connectionDone = NO;
            while (!connectionDone&&![self isCancelled]) {
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
            }
        }
        [connection release];
        connection = nil;
    }
}

- (void)cancel{
    [super cancel];
    [connection cancel];
    [connection release];
    connection = nil;
    [self failedWithError:[self errorWithCode:kWBSDKErrorCodeRequestCanceled userInfo:nil]];
}

- (NSURLConnection *)beginConnection{
    NSMutableDictionary *urlParams = [NSMutableDictionary dictionaryWithDictionary:params];
    if (needAuthorize&&self.weiboEngine.accessToken) {
        [urlParams setObject:self.weiboEngine.accessToken forKey:@"access_token"];
    }
    NSString *usersShowUrl = [NSString stringWithFormat:@"%@users/show.json",kWBSDKAPIDomain];
    if ([self.url isEqualToString:usersShowUrl]) {
        [urlParams setObject:self.weiboEngine.userID forKey:@"uid"];
    }
    NSString *urlString = [NSString WBRequestURLWithBaseURL:url params:urlParams httpMethod:httpMethod];
//    GHDINFO(@"loading %@",urlString);
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
														   cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
													   timeoutInterval:kWBRequestTimeOutInterval];
    
    [request setHTTPMethod:httpMethod];
    if ([httpMethod isEqualToString:@"POST"])
    {
        if (postDataType == kWBRequestPostDataTypeMultipart)
        {
            NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", kWBRequestStringBoundary];
            [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
        }
        
        [request setHTTPBody:[self postData]];
    }
    
    for (NSString *key in [httpHeaderFields keyEnumerator]){
        [request setValue:[httpHeaderFields objectForKey:key] forHTTPHeaderField:key];
    }
    
    return [[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES] autorelease];
}

- (NSData *)postData{
    NSMutableData *body = [NSMutableData data];
    NSMutableDictionary *postParams = [NSMutableDictionary dictionaryWithDictionary:params]; 
    if (needAuthorize&&self.weiboEngine.accessToken) {
        [postParams setObject:self.weiboEngine.accessToken forKey:@"access_token"];
    }
    if (postDataType == kWBRequestPostDataTypeNormal){
        [body appendData:[[NSString WBParamstringWithDictionary:postParams] dataUsingEncoding:NSUTF8StringEncoding]];
    }
    else if (postDataType == kWBRequestPostDataTypeMultipart)
    {
        NSString *bodyPrefixString = [NSString stringWithFormat:@"--%@\r\n", kWBRequestStringBoundary];
        NSString *bodySuffixString = [NSString stringWithFormat:@"\r\n--%@--\r\n", kWBRequestStringBoundary];
        
        NSMutableDictionary *dataDictionary = [NSMutableDictionary dictionary];
        
        [body appendData:[bodyPrefixString dataUsingEncoding:NSUTF8StringEncoding]];
        
        for (id key in [postParams keyEnumerator]) 
        {
            if (([[postParams valueForKey:key] isKindOfClass:[UIImage class]]) || ([[postParams valueForKey:key] isKindOfClass:[NSData class]]))
            {
                [dataDictionary setObject:[postParams valueForKey:key] forKey:key];
                continue;
            }
            NSString *string = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n", key, [postParams valueForKey:key]];
            
            [body appendData:[string dataUsingEncoding:NSUTF8StringEncoding]];
            [body appendData:[bodyPrefixString dataUsingEncoding:NSUTF8StringEncoding]];
        }
        
        if ([dataDictionary count] > 0) 
        {
            for (id key in dataDictionary) 
            {
                NSObject *dataParam = [dataDictionary valueForKey:key];
                
                if ([dataParam isKindOfClass:[UIImage class]]) 
                {
                    NSData* imageData = UIImagePNGRepresentation((UIImage *)dataParam);
                    NSString *position = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"file.png\"\r\n", key];
                    [body appendData:[position dataUsingEncoding:NSUTF8StringEncoding]];
                    NSString *info=@"Content-Type: image/png\r\nContent-Transfer-Encoding: binary\r\n\r\n";
                    [body appendData:[info dataUsingEncoding:NSUTF8StringEncoding]];
                    [body appendData:imageData];
                } 
                else if ([dataParam isKindOfClass:[NSData class]]) {
                    NSString *position = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", key];
                    [body appendData:[position dataUsingEncoding:NSUTF8StringEncoding]];
                    NSString *info=@"Content-Type: content/unknown\r\nContent-Transfer-Encoding: binary\r\n\r\n";
                    [body appendData:[info dataUsingEncoding:NSUTF8StringEncoding]];
                    [body appendData:(NSData*)dataParam];
                }
                [body appendData:[bodySuffixString dataUsingEncoding:NSUTF8StringEncoding]];
            }
        }
    }
    return body;
}

- (id)getObjectFromJsonData:(NSData *)data error:(NSError **)error{
	NSError *parseError;
	id result = [data objectFromJSONDataWithParseOptions:JKParseOptionStrict error:&parseError];
	if (parseError)
    {
        if (error != nil)
        {
            *error = [self errorWithCode:kWBErrorCodeSDK
                                userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%d", kWBSDKErrorCodeParseError]
                                                                     forKey:kWBSDKErrorCodeKey]];
        }
	}
    
	if ([result isKindOfClass:[NSDictionary class]]){
		if ([result objectForKey:@"error_code"] != nil && [[result objectForKey:@"error_code"] intValue] != 200)
		{
			if (error != nil) 
			{
				*error = [self errorWithCode:kWBErrorCodeInterface userInfo:result];
			}
		}
	}
	return result;
}

- (void)handleResponseData:(NSData *)data{
    if ([_delegate respondsToSelector:@selector(WeiboRequest:didReceiveRawData:)]){
        dispatch_sync(dispatch_get_main_queue(), ^{
            [_delegate WeiboRequest:self didReceiveRawData:data];  
        });
    }
    if (requestResult) {
        [requestResult release];
        requestResult = nil;
    }
    
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    [dic setObject:data forKey:kWBRequestResultData];
    
    NSError *error = nil;
	id result = [self getObjectFromJsonData:data error:&error];
	
    if (result) {
        [dic setObject:result forKey:kWBRequestResultJsonData];
    }
    
	if (error){
        [dic setObject:error forKey:kWBRequestResultError];
	}
    
    if ([result isKindOfClass:[NSDictionary class]]) {
        NSString *errorString = [result objectForKey:@"error"];
        if (errorString) {
            if ([errorString isEqualToString:@"invalid_access_token"]){
                [self.weiboEngine logOut];
            }
        }   
    }
    
    requestResult = [[NSDictionary dictionaryWithDictionary:dic] retain];
    if ([_delegate respondsToSelector:@selector(WeiboRequest:didFinishLoadingWithResult:)]){
        dispatch_sync(dispatch_get_main_queue(), ^{
            [_delegate WeiboRequest:self didFinishLoadingWithResult:requestResult];
        });
    }
}

- (id)errorWithCode:(NSInteger)code userInfo:(NSDictionary *)userInfo{
    return [NSError errorWithDomain:kWBSDKErrorDomain code:code userInfo:userInfo];
}

- (void)failedWithError:(NSError *)error {
	if ([_delegate respondsToSelector:@selector(WeiboRequest:didFailWithError:)]) 
	{
        if ([[NSThread currentThread] isMainThread]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [_delegate WeiboRequest:self didFailWithError:error];
            });
        }else {
            dispatch_sync(dispatch_get_main_queue(), ^{
                [_delegate WeiboRequest:self didFailWithError:error];
            });   
        }
	}
}

#pragma mark URLConnection
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
	responseData = [[NSMutableData alloc] init];
	if ([_delegate respondsToSelector:@selector(WeiboRequest:didReceiveResponse:)]){
		[_delegate WeiboRequest:self didReceiveResponse:response];
	}
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
	[responseData appendData:data];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
				  willCacheResponse:(NSCachedURLResponse*)cachedResponse{
	return nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection {
	[self handleResponseData:responseData];
    
	[responseData release];
	responseData = nil;
    
    [connection cancel];
	[connection release];
	connection = nil;
    connectionDone = YES;
}

- (void)connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error{
	[self failedWithError:error];
	
	[responseData release];
	responseData = nil;
    
    [connection cancel];
	[connection release];
	connection = nil;
    connectionDone = YES;
}
@end

@interface GHWeiboEngine()<AuthorizeWebViewDelegate,GHWeiboRequestDelegate>{
    
}
- (void)saveAuthorizeDataToKeychain;
- (void)readAuthorizeDataFromKeychain;
- (void)deleteAuthorizeDataInKeychain;
- (NSString *)serviceName;
@end

@implementation GHWeiboEngine

SYNTHESIZE_SINGLETON_FOR_CLASS(GHWeiboEngine);

@synthesize userExclusive = _userExclusive;
@synthesize userID;
@synthesize appKey;
@synthesize redirectURI;
@synthesize delegate = _delegate;
@synthesize expireTime;
@synthesize appSecret;
@synthesize accessToken;
@synthesize isLogined;
@synthesize requests;

- (id)init
{
    if (self = [super init]) {
        appKey = [kSinaWeiboAppKey copy];
        appSecret = [kSinaWeiboAppSecret copy];
        [self setRedirectURI:@"http://"];
        _userExclusive = YES;
        [self readAuthorizeDataFromKeychain];
    }
    return self;
}

//- (id)initWithAppKey:(NSString *)theAppKey appSecret:(NSString *)theAppSecret{
//    if (self = [self init]){
//        appKey = [theAppKey copy];
//        appSecret = [theAppSecret copy];
//        [self setRedirectURI:@"http://"];
//        _userExclusive = YES;
//        [self readAuthorizeDataFromKeychain];
//    }
//    return self;
//}


- (void)dealloc{
    for (GHWeiboRequest *request in requests.operations) {
        if (request.delegate == self) {
            request.delegate = nil;
        }
    }
    [requests cancelAllOperations];
    [requests release];
    
    self.delegate = nil;
    [appKey release], appKey = nil;
    [appSecret release], appSecret = nil;
    [userID release], userID = nil;
    [accessToken release], accessToken = nil;
    [redirectURI release], redirectURI = nil;
    
    requests = nil;
    [super dealloc];
}

- (NSString *)serviceName{
    NSString *serviceName = [NSString stringWithFormat:@"%@%@%@",kWBURLSchemePrefix,appKey,kWBKeychainServiceNameSuffix];
    return serviceName;
}

- (void)saveAuthorizeDataToKeychain{
    NSString *serviceName = [self serviceName];
    
    [SFHFKeychainUtils storeUsername:kWBKeychainUserID 
                         andPassword:userID
                      forServiceName:serviceName
                      updateExisting:YES
                               error:nil];
    
	[SFHFKeychainUtils storeUsername:kWBKeychainAccessToken 
                         andPassword:accessToken
                      forServiceName:serviceName
                      updateExisting:YES
                               error:nil];
    
	[SFHFKeychainUtils storeUsername:kWBKeychainExpireTime
                         andPassword:[NSString stringWithFormat:@"%lf", expireTime]
                      forServiceName:serviceName
                      updateExisting:YES
                               error:nil];
}

- (void)readAuthorizeDataFromKeychain{
    NSString *serviceName = [self serviceName];
    
    [userID release];
    userID = [[SFHFKeychainUtils getPasswordForUsername:kWBKeychainUserID andServiceName:serviceName error:nil] copy];
    
    [accessToken release];
    accessToken = [[SFHFKeychainUtils getPasswordForUsername:kWBKeychainAccessToken andServiceName:serviceName error:nil] copy];
    
    expireTime = [[SFHFKeychainUtils getPasswordForUsername:kWBKeychainExpireTime 
                                             andServiceName:serviceName 
                                                      error:nil] doubleValue];
    if ([self isLogined]) {
        if ([_delegate respondsToSelector:@selector(engineAlreadyLoggedIn:)]) {
            [_delegate engineAlreadyLoggedIn:self];
        }
    }
}

- (void)setDelegate:(id<GHWeiboEngineDelegate>)delegate{
    if (_delegate != delegate) {
        _delegate = delegate;
        if ([self isLogined]) {
            [_delegate engineAlreadyLoggedIn:self];
        }
    }
}

- (void)deleteAuthorizeDataInKeychain{
    [userID release];
    userID = nil;
    
    [accessToken release];
    accessToken = nil;
    
    expireTime = 0;
    
    NSString *serviceName = [self serviceName];
    [SFHFKeychainUtils deleteItemForUsername:kWBKeychainUserID andServiceName:serviceName error:nil];
	[SFHFKeychainUtils deleteItemForUsername:kWBKeychainAccessToken andServiceName:serviceName error:nil];
	[SFHFKeychainUtils deleteItemForUsername:kWBKeychainExpireTime andServiceName:serviceName error:nil];
}

- (void)logIn{
    //if (logging) {
    //    return;
    //}
    if ([self isLogined]) {
        if ([_delegate respondsToSelector:@selector(engineAlreadyLoggedIn:)])
        {
            [_delegate engineAlreadyLoggedIn:self];
        }
        if (self.isUserExclusive)
        {
            return;
        }
    }
    GHWeiboAuthorizeWebView *authorizeView = [[GHWeiboAuthorizeWebView alloc] init];
    authorizeView.delegate = self;

    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:appKey, @"client_id",
                            @"code", @"response_type",
                            redirectURI,@"redirect_uri",nil];
    
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        [params setObject:@"mobile" forKey:@"display"];
    }
    
    NSString *urlString = [NSString WBRequestURLWithBaseURL:kWBAuthorizeURL
                                                     params:params
                                                 httpMethod:@"GET"];
    [authorizeView loadRequestWithURL:[NSURL URLWithString:urlString]];
    [authorizeView show:YES];
    logging = YES;
    [authorizeView release];
}

- (void)logInUsingUserID:(NSString *)theUserID password:(NSString *)thePassword{
    [userID release];
    userID = [theUserID retain];
    
    if ([self isLogined])
    {
        if ([_delegate respondsToSelector:@selector(engineAlreadyLoggedIn:)])
        {
            [_delegate engineAlreadyLoggedIn:self];
        }
        if (_userExclusive)
        {
            return;
        }
    }
    logging = YES;
    [self requestAccessTokenWithUserID:theUserID password:thePassword];
}

- (void)logOut{
    GHWeiboRequest *request = [GHWeiboRequest apiRequestWithMethod:@""
                                                        httpMethod:@"GET"
                                                            params:nil
                                                      postDataType:kWBRequestPostDataTypeNormal
                                                  httpHeaderFields:nil
                                                        identifier:@"logout"
                                                          delegate:self
                                                     needAuthorize:YES];
    
    [self addRequest:request];
    
    [self deleteAuthorizeDataInKeychain];
    
    if ([_delegate respondsToSelector:@selector(engineDidLogOut:)]){
        dispatch_async(dispatch_get_main_queue(), ^{
            [_delegate engineDidLogOut:self];
        });
    }
}

- (BOOL)isLogined{
    return userID && accessToken && (![self isAuthorizeExpired]);
}

- (NSString *)accessToken{
    if ([self isLogined]) {
        return accessToken;
    }
    return nil;
}

- (BOOL)isAuthorizeExpired{
    if ([[NSDate date] timeIntervalSince1970] > expireTime)
    {
        [self deleteAuthorizeDataInKeychain];
        return YES;
    }
    return NO;
}

- (void)addRequest:(GHWeiboRequest *)request{
    if (!request) {
        return;
    }
    if (!requests) {
        requests = [[NSOperationQueue alloc] init];
    }
    request.weiboEngine = self;
    [requests addOperation:request];
}

- (void)cancelAllRequest{
    [requests cancelAllOperations];
}

- (void)cancelRequestWithIdentifier:(NSString *)identifier{
    for (NSOperation *operation in requests.operations) {
        if ([[(GHWeiboRequest *)operation identifier] isEqualToString:identifier]) {
            [operation cancel];
        }
    }
}

- (NSArray *)requestsWithIdentifer:(NSString *)identifier{
    NSMutableArray *array = [NSMutableArray array];
    for (NSOperation *operation in requests.operations) {
        if ([[(GHWeiboRequest *)operation identifier] isEqualToString:identifier]) {
            [array addObject:operation];
        }
    }
    if (array.count>0) {
        return [NSArray arrayWithArray:array];
    }
    return nil;
}

- (void)authorizeWebView:(GHWeiboAuthorizeWebView *)webView didReceiveAuthorizeCode:(NSString *)code{
    [webView hide:YES];
    [self requestAccessTokenWithAuthorizeCode:code];
}

- (void)authorizeWebViewCanceled:(GHWeiboAuthorizeWebView *)webView{
    NSError *error = [NSError errorWithDomain:kWBSDKErrorDomain 
                                         code:kWBErrorCodeSDK 
                                     userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%d", kWBSDKErrorCodeRequestCanceled] 
                                                                          forKey:kWBSDKErrorCodeKey]];
    [_delegate engine:self didFailToLogInWithError:error];
}

- (void)requestAccessTokenWithAuthorizeCode:(NSString *)code{
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:appKey, @"client_id",
                            appSecret, @"client_secret",
                            @"authorization_code", @"grant_type",
                            redirectURI, @"redirect_uri",
                            code, @"code", nil];
    
    GHWeiboRequest *request = [GHWeiboRequest requestWithURL:kWBAccessTokenURL
                                                  httpMethod:@"POST"
                                                      params:params
                                                postDataType:kWBRequestPostDataTypeNormal
                                            httpHeaderFields:nil 
                                                  identifier:kLoginRequestIdentifier
                                                    delegate:self];
    
    [self addRequest:request];
}

- (void)requestAccessTokenWithUserID:(NSString *)userID_ password:(NSString *)password{
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:appKey, @"client_id",
                            appSecret, @"client_secret",
                            @"password", @"grant_type",
                            redirectURI, @"redirect_uri",
                            userID_, @"username",
                            password, @"password",nil];
    
    
    GHWeiboRequest *request = [GHWeiboRequest requestWithURL:kWBAccessTokenURL
                                                  httpMethod:@"POST"
                                                      params:params
                                                postDataType:kWBRequestPostDataTypeNormal
                                            httpHeaderFields:nil 
                                                  identifier:kLoginRequestIdentifier
                                                    delegate:self];
    [self addRequest:request];
}

#pragma mark requestDelegate
- (void)WeiboRequest:(GHWeiboRequest *)request didReceiveResponse:(NSURLResponse *)response{
    
}

- (void)WeiboRequest:(GHWeiboRequest *)request didReceiveRawData:(NSData *)data{
    
}

- (void)WeiboRequest:(GHWeiboRequest *)request didFailWithError:(NSError *)error{
    if ([request.identifier isEqualToString:kLoginRequestIdentifier]) {
        NSError *error = [NSError errorWithDomain:kWBSDKErrorDomain 
                                             code:kWBErrorCodeSDK 
                                         userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%d", kWBSDKErrorCodeAuthorizeError] 
                                                                              forKey:kWBSDKErrorCodeKey]];
        [_delegate engine:self didFailToLogInWithError:error];
    }
}

- (void)WeiboRequest:(GHWeiboRequest *)request didFinishLoadingWithResult:(id)result{
    if ([request.identifier isEqualToString:kLoginRequestIdentifier]) {
        BOOL success = NO;
        if ([result isKindOfClass:[NSDictionary class]]){
            NSDictionary *dict = [(NSDictionary *)result objectForKey:kWBRequestResultJsonData];
            
            NSString *token = [dict objectForKey:@"access_token"];
            NSString *uid = [dict objectForKey:@"uid"];
            NSInteger seconds = [[dict objectForKey:@"expires_in"] intValue];
            
            success = token && uid;
            
            if (success) {
                [accessToken release];
                accessToken = [token copy];
                [userID release];
                userID = [uid copy];
                expireTime = [[NSDate date] timeIntervalSince1970] + seconds;
                [self saveAuthorizeDataToKeychain];
                if ([_delegate respondsToSelector:@selector(engineDidLogIn:)]) {
                    [_delegate engineDidLogIn:self];
                }
                [[NSNotificationCenter defaultCenter] postNotificationName:kGHWeiboEngineLoginedNotification object:self];
            }
        }
        
        if (!success && [_delegate respondsToSelector:@selector(engine:didFailToLogInWithError:)])
        {
            NSError *error = [NSError errorWithDomain:kWBSDKErrorDomain 
                                                 code:kWBErrorCodeSDK 
                                             userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%d", kWBSDKErrorCodeAuthorizeError] 
                                                                                  forKey:kWBSDKErrorCodeKey]];
            [_delegate engine:self didFailToLogInWithError:error];
        }
    }
}
@end
